package com.geekchique.runningbuddy.activity.stopwatch;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

public class StopwatchTools {

	private static final int SECONDS_IN_MINUTE = 60;
	private static final int CENTISECONDS_IN_MINUTE = 1060;
	private static final int SECONDS_IN_HOUR = 3600;
	private static final int HOURS_IN_A_DAY = 24;
	private static final int MILLISEC_IN_SEC = 1000;
	private static final int MILLISEC_IN_MIN = 60 * MILLISEC_IN_SEC;
	private static final int MILLISEC_IN_HOUR = 60 * MILLISEC_IN_MIN;
	private static final int DAYS_IN_A_YEAR = 365;
	public static final int HOUR_THRESHHOLD = 24;
	public static final int MINUTE_THRESHHOLD = 59;
	public static final int SECOND_THRESHHOLD = 59;
	public static final int CENTISEC_THRESHHOLD = 99;
	public static final int LOWEST_POSSIBLE = 00;
	private static final int TWO_DIGITS_TEN = 10;
	public static final Locale locale = new Locale("UK");

	public static final int EQUAL = 0;
	public static final int GREATER_THAN = 1;
	public static final int LESS_THAN = -1;

	public static final int CENTISECS = 0;
	public static final int SECS = 1;
	public static final int MINS = 2;
	public static final int HOURS = 3;

//This needs refactoring
	public static String updateFormattedString(String ammendmentOperator, String currentTime, Integer incrementType, int byAmount) {

		String numericValue = null;

		switch(incrementType){
			case StopwatchTools.CENTISECS:

				if(getCentiSecs(currentTime) == CENTISEC_THRESHHOLD && ammendmentOperator.equals("++")){


					if(getSecs(currentTime) == SECOND_THRESHHOLD){

						if(getMins(currentTime) == MINUTE_THRESHHOLD){
							currentTime = setHours(Integer.parseInt(incrementHours(ammendmentOperator, currentTime, 1)), currentTime);
							currentTime = setMins(0, currentTime);
							currentTime = setSecs(0, currentTime);
							currentTime = setCentiSecs(0, currentTime);
						}else{
							//increment secs
							currentTime = setMins(Integer.parseInt(incrementMins(ammendmentOperator, currentTime, 1)), currentTime);
							currentTime = setSecs(0, currentTime);
							currentTime = setCentiSecs(0, currentTime);
						}

					}else{
						currentTime = setSecs(Integer.parseInt(incrementSeconds(ammendmentOperator, currentTime, 1)), currentTime);
						currentTime = setCentiSecs(0, currentTime);
					}

				}else{
					numericValue = incrementCentiSeconds(ammendmentOperator, currentTime, 1);
					currentTime = setCentiSecs(Integer.parseInt(numericValue), currentTime);
				}
				break;



			case StopwatchTools.SECS:
				if(getSecs(currentTime) == SECOND_THRESHHOLD && ammendmentOperator.equals("++")){
					currentTime = setMins(Integer.parseInt(incrementMins(ammendmentOperator, currentTime, 1)), currentTime);
					currentTime = setSecs(0, currentTime);
				}else{
					numericValue = incrementSeconds(ammendmentOperator, currentTime, 1);
					currentTime = setSecs(Integer.parseInt(numericValue), currentTime);
				}
				break;
			case StopwatchTools.MINS:
				if(getMins(currentTime) == MINUTE_THRESHHOLD && ammendmentOperator.equals("++")){
					numericValue = setHours(Integer.parseInt(incrementHours(ammendmentOperator, currentTime, 1)), currentTime);
					currentTime = setMins(0, currentTime);
				}else{
					numericValue = incrementMins(ammendmentOperator, currentTime, 1);
					currentTime = setMins(Integer.parseInt(numericValue), currentTime);
				}
				break;
			case StopwatchTools.HOURS:
				numericValue = incrementHours(ammendmentOperator, currentTime, 1);
				currentTime = setHours(Integer.parseInt(numericValue), currentTime);
				break;
		}

		return currentTime;

	}

	private static String incrementCentiSeconds(String ammendmentOperator, String currentTime, int byAmount) {
		Integer digits = getCentiSecs(currentTime);
		return incrementWithoutRolling(ammendmentOperator, byAmount, digits, CENTISEC_THRESHHOLD, LOWEST_POSSIBLE);
	}

	protected static String incrementSeconds(String ammendmentOperator, String currentTime, int byAmount) {
		Integer digits = getSecs(currentTime);
		return incrementWithoutRolling(ammendmentOperator, byAmount, digits, SECOND_THRESHHOLD, LOWEST_POSSIBLE);
	}

	private static String incrementMins(String ammendmentOperator, String currentTime, int byAmount) {
		Integer digits = getMins(currentTime);
		return incrementWithoutRolling(ammendmentOperator, byAmount, digits, MINUTE_THRESHHOLD, LOWEST_POSSIBLE);
	}

	private static String incrementHours(String ammendmentOperator, String currentTime, int byAmount) {
		Integer digits = getHours(currentTime);
		return incrementWithoutRolling(ammendmentOperator, byAmount, digits, HOUR_THRESHHOLD, LOWEST_POSSIBLE);
	}

	private static String incrementWithoutRolling(String operator, int byAmount, Integer digitsInTime, int highestThreshold, int lowestThreshold) {
		for(int i=0; i<byAmount; i++){
			digitsInTime = new Integer(digitsAmmendedByOperator(digitsInTime, operator, highestThreshold, lowestThreshold));
		}

		return stringOfIntInExpectedFormat(digitsInTime);
	}

	public static String updateSecs(String operator, String currentTime) {

		String returnedTime = null;

		String hours = getHoursString(currentTime);
		String mins = getMinsString(currentTime);
		Integer secs = getSecs(currentTime);
		String centiSecs = getCentiSecsString(currentTime);

		String returnedDigits = digitsAmmendedByOperator(secs, operator, SECOND_THRESHHOLD, LOWEST_POSSIBLE);

		if(returnedDigits.equals(SECOND_THRESHHOLD)){
			returnedTime = "00:00:00.00";
		}else{
			returnedTime = new String(hours + ":" + mins + ":" + returnedDigits + "." + centiSecs);
		}

		return returnedTime;

	}

	public static String updateCentiSecs(String operator, String currentTime) {

		String returnedTime = null;

		String hours = getHoursString(currentTime);
		String mins = getMinsString(currentTime);
		String secs = getSecsString(currentTime);
		Integer centiSecs = getCentiSecs(currentTime);

		String returnedDigits = digitsAmmendedByOperator(centiSecs, operator, CENTISEC_THRESHHOLD, LOWEST_POSSIBLE);

		if(returnedDigits.equals(SECOND_THRESHHOLD)){
			returnedTime = "00:00:00.00";
		}else{
			returnedTime = new String(hours + ":" + mins + ":" + secs + "." + returnedDigits);
		}

		return returnedTime;

	}

	public static String updateMins(String operator, String currentTime) {

		String returnedTime = null;
		String mins = null;
		String hours = null;

		Integer newTime = getMins(currentTime);

		if( getHours(currentTime) < 10 ){
			hours = "0" + getHours(currentTime.toString());
		}else{
			hours = getHours(currentTime).toString();
		}

		String end = getAfterMins(currentTime);
		mins = digitsAmmendedByOperator(newTime, operator, MINUTE_THRESHHOLD, LOWEST_POSSIBLE);

		if(mins.equals(MINUTE_THRESHHOLD)){
			returnedTime = "00:00:00.00";
		}else{
			returnedTime = new String(hours + ":" + mins + end);
		}

		return returnedTime;

	}

	public static String updateHours(String operator, String currentTime) {

		String returnedTime = null;
		String hours = null;

		Integer newTime = getHours(currentTime);
		String other = getEverythingButHours(currentTime);
		hours = digitsAmmendedByOperator(newTime, operator, HOUR_THRESHHOLD, LOWEST_POSSIBLE);

		if(hours.equals("0")){
			hours = hours.concat("0");
		}

		returnedTime = new String( hours + other);

		return returnedTime;

	}

	public static String getAfterMins(String currentTime) {
		return currentTime.substring(5);
	}

	public static String digitsAmmendedByOperator(Integer digitsInTime, String operator, int highest_poss, int lowest_poss) {
		String centiSecs = null;

		if(operator.equals("++")){
			if (digitsInTime == highest_poss){
				centiSecs = stringOfIntInExpectedFormat(new Integer(lowest_poss));
			}else{
				digitsInTime++;
				digitsInTime = setNoWithRoller(digitsInTime, highest_poss);
				centiSecs =  stringOfIntInExpectedFormat(digitsInTime);
			}
		}

		if(operator.equals("--")){
			if (digitsInTime == lowest_poss){
				centiSecs = stringOfIntInExpectedFormat(new Integer(lowest_poss));
			}else{
				digitsInTime--;
				centiSecs = stringOfIntInExpectedFormat(digitsInTime);
			}
		}

		return centiSecs;
	}

	public static String getEverythingButHours(String currentTime) {
		return currentTime.substring(2);
	}

	public static Integer setNoWithRoller(Integer newTime, int roller) {

		if((newTime + newTime)  < roller){
			return newTime++;
		}else{

			while(newTime > roller){
				newTime = (newTime - roller);
			}

			if(newTime > roller){
				return new Integer(0);
			}

		}

		return newTime;
	}

	public static String stringOfIntInExpectedFormat(Integer newTime) {
		String secs;

		if (newTime < TWO_DIGITS_TEN){
			secs =  (newTime).toString();
			secs = "0" + secs;
		}else{
			secs =  (newTime).toString();
		}

		return secs;
	}

	public static Integer getCentiSecs(String formattedTime){
		return new Integer(stringOfIntInExpectedFormat(Integer.parseInt(formattedTime.substring(9, 11))));
	}

	public static String getCentiSecsString(String formattedTime){
		return stringOfIntInExpectedFormat(Integer.parseInt(formattedTime.substring(9, 11)));
	}

	public static Integer getSecs(String formattedString) {
		return new Integer(stringOfIntInExpectedFormat(Integer.parseInt(formattedString.substring(6, 8))));
	}

	public static String getSecsString(String formattedString) {
		return stringOfIntInExpectedFormat(Integer.parseInt(formattedString.substring(6, 8)));
	}

	public static String getMinsString(String formattedString) {
		return stringOfIntInExpectedFormat(Integer.parseInt(formattedString.substring(3, 5)));
	}

	public static Integer getMins(String formattedString) {
		return new Integer(stringOfIntInExpectedFormat(Integer.parseInt(formattedString.substring(3, 5))));
	}

	public static String getHoursString(String formattedString) {
		return stringOfIntInExpectedFormat(Integer.parseInt(formattedString.substring(0, 2)));
	}

	public static Integer getHours(String formattedString) {
		return new Integer(stringOfIntInExpectedFormat(Integer.parseInt(formattedString.substring(0, 2))));
	}

	public static String setHours(Integer hours, String formattedString) {

		StringBuffer stringBuffer = new StringBuffer(formattedString);

		if(hours < 00 || hours > HOUR_THRESHHOLD)
		{
			stringBuffer.replace(0, 3, hours.toString());
			stringBuffer.insert(0, "00");
			return stringBuffer.toString();
		}
		else if( hours < 10)
		{
			stringBuffer.replace(0, 2, hours.toString());
			stringBuffer.insert(0, "0");
			return stringBuffer.toString();
		}

		stringBuffer.replace(0, 2, hours.toString());
		return stringBuffer.toString();
	}

	public static String setSecs(Integer secs, String formattedString) {
		StringBuffer stringBuffer = new StringBuffer(formattedString);

		if(secs < 00 || secs > SECOND_THRESHHOLD)
		{
			stringBuffer.replace(6, 9, secs.toString());
			stringBuffer.insert(6, "00");
			return stringBuffer.toString();
		}
		else if( secs < 10)
		{
			stringBuffer.replace(6, 8, secs.toString());
			stringBuffer.insert(6, "0");
			return stringBuffer.toString();
		}

		stringBuffer.replace(6, 8, secs.toString());
		return stringBuffer.toString();
	}

	public static String setMins(Integer mins, String formattedString) {
		StringBuffer stringBuffer = new StringBuffer(formattedString);

		if(mins < 00 || mins > MINUTE_THRESHHOLD)
		{
			stringBuffer.replace(3, 6, mins.toString());
			stringBuffer.insert(3, "00");
			return stringBuffer.toString();
		}
		else if( mins < 10)
		{
			stringBuffer.replace(3, 5, mins.toString());
			stringBuffer.insert(3, "0");
			return stringBuffer.toString();
		}

		stringBuffer.replace(3, 5, mins.toString());
		return stringBuffer.toString();
	}

	public static String setCentiSecs(Integer centiSecs, String formattedString) {

		StringBuffer stringBuffer = new StringBuffer(formattedString);

		if(centiSecs < 00 || centiSecs > CENTISEC_THRESHHOLD)
		{
			stringBuffer.replace(9, 12, centiSecs.toString());
			stringBuffer.insert(9, "00");
			return stringBuffer.toString();
		}
		else if( centiSecs < 10)
		{
			stringBuffer.replace(9, 11, centiSecs.toString());
			stringBuffer.insert(9, "0");
			return stringBuffer.toString();
		}

		stringBuffer.replace(9, 11, centiSecs.toString());
		return stringBuffer.toString();
	}

	public static int compare(String timeYouCareAbout, String comparison) {

		long target = getMilliSecs(timeYouCareAbout);
		long againstThis = getMilliSecs(comparison);

		if(againstThis == target ){
			return EQUAL;
		}

		if(againstThis > target){
			return GREATER_THAN;
		}

		if(againstThis < target){
			return LESS_THAN;
		}

		return 0;
	}

	public static String getTimeInExpectedFormat(long time) {
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTimeInMillis(time);
		SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
		String formattedDate = dateFormat.format(calendar.getTime());
		return formattedDate;
	}

	public static long getMilliSecs(String formattedString) {
		Calendar calendar = new GregorianCalendar();
		calendar.set(Calendar.YEAR, 0);
		calendar.set(Calendar.MONTH, 0);
		calendar.set(Calendar.DAY_OF_MONTH, 1);

		calendar.set(Calendar.HOUR, getHours(formattedString));
		calendar.set(Calendar.MINUTE, getMins(formattedString));
		calendar.set(Calendar.SECOND, getSecs(formattedString));
		calendar.set(Calendar.MILLISECOND, getCentiSecs(formattedString));

		return calendar.getTimeInMillis();
	}

	public static boolean inTheSameDay(long time1, long time2) {
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTimeInMillis(time1);

		GregorianCalendar cal2 = new GregorianCalendar();
		cal2.setTimeInMillis(time2);

		if ( cal.get(java.util.Calendar.YEAR) == cal2.get(java.util.Calendar.YEAR) && cal.get(java.util.Calendar.DAY_OF_YEAR) == cal2.get(java.util.Calendar.DAY_OF_YEAR)) {
			return true;
		}

		return false;
	}

	public static long getDiffMilli(long before, long after) {
		return after - before;
	}

	public static Long getDiffSecs(long before, long after) {
		return new Long(getDiffMilli(before, after) / MILLISEC_IN_SEC);
	}

	public static Long getDiffMins(long before, long after) {
		return new Long(getDiffMilli(before, after)  / MILLISEC_IN_MIN);
	}

	public static Long getDiffHours(long before, long after) {
		return new Long(getDiffMilli(before, after) / MILLISEC_IN_HOUR);
	}

	public static Long getDiffDays(long before, long after) {
		return new Long(getDiffHours(before, after) / HOURS_IN_A_DAY);
	}

	public static Long getDiffYears(long before, long after) {
		return new Long(getDiffDays(before, after) / DAYS_IN_A_YEAR);
	}


	public static String getFormattedDiff(long before, long after) {

		GregorianCalendar beforeCal = new GregorianCalendar();
		GregorianCalendar afterCal = new GregorianCalendar();

		beforeCal.setTimeInMillis(before);
		afterCal.setTimeInMillis(after);

		long elapsed = getElapsedSeconds(beforeCal, afterCal);

		return formattedCalcHMS(elapsed);
	}

	public static long[] getDiff(long before, long after) {

		GregorianCalendar beforeCal = new GregorianCalendar();
		GregorianCalendar afterCal = new GregorianCalendar();

		beforeCal.setTimeInMillis(before);
		afterCal.setTimeInMillis(after);

		long elapsed = getElapsedSeconds(beforeCal, afterCal);

		return calcHMS(elapsed);
	}

	//Not accurate enough.
	 public static long getElapsedSeconds(GregorianCalendar gc1, GregorianCalendar gc2) {
	      Date d1 = gc1.getTime();
	      Date d2 = gc2.getTime();
	      long l1 = d1.getTime();
	      long l2 = d2.getTime();
	      long difference = Math.abs(l2 - l1);
	      return difference / 1000;
	  }

	   //ToDo: This function is not generating the expected result. Somehow there is rounding taking place that involves the parts of the seonds that I have not printed.
	   //Even if I could just print them that would be fine.
	   public static String formattedCalcHMS(long timeInSeconds) {
		      long hours, minutes, seconds, secondsLeftOver;

		      hours = timeInSeconds / SECONDS_IN_HOUR;
		      secondsLeftOver = timeInSeconds - (hours * SECONDS_IN_HOUR);

		      minutes = secondsLeftOver / SECONDS_IN_MINUTE;
		      seconds = secondsLeftOver - (minutes * SECONDS_IN_MINUTE);

		      return hours + " Hours " + minutes + " mins " + seconds + " secs";
	   }


	   public static long[] calcHMS(long timeInSeconds) {

		   int hoursArray = 3, minutesArray = 2, secondsArray = 1, centiArray = 0;
		   long hours = 0, minutes = 0, seconds = 0, centi = 0;
		   long secondsLeftOver;
		   long[] hoursMinSecsCenti = {0,0,0,0};

		   hours = timeInSeconds / SECONDS_IN_HOUR;
		   secondsLeftOver = timeInSeconds - (hours * SECONDS_IN_HOUR);

		   minutes = secondsLeftOver / SECONDS_IN_MINUTE;
		   seconds = secondsLeftOver - (minutes * SECONDS_IN_MINUTE);
		   centi = secondsLeftOver - (minutes * CENTISECONDS_IN_MINUTE);


		   hoursMinSecsCenti[centiArray] = centi;
		   hoursMinSecsCenti[secondsArray]= seconds;
		   hoursMinSecsCenti[minutesArray]= minutes;
		   hoursMinSecsCenti[hoursArray]= hours;

		   return hoursMinSecsCenti;
	   }

//	   public static String[] calcHMSAsStrings(long timeInSeconds) {
//		   long hours, minutes, seconds, secondsLeftOver;
//		   String[] hoursMinSecsCenti = {"","","",""};
//
//		   hours = timeInSeconds / SECONDS_IN_HOUR;
//		   secondsLeftOver = timeInSeconds - (hours * SECONDS_IN_HOUR);
//
//		   minutes = secondsLeftOver / SECONDS_IN_MINUTE;
//		   seconds = secondsLeftOver - (minutes * SECONDS_IN_MINUTE);
//
//		   hoursMinSecsCenti[0] = Long.toString(hours);
//		   hoursMinSecsCenti[1] = Long.toString(minutes);
//		   hoursMinSecsCenti[2] = Long.toString(seconds);
//		   hoursMinSecsCenti[3] = "00";
//
//		   return hoursMinSecsCenti;
//	   }




}
